﻿#!/usr/bin/env python
# ------------------------------------------------------------------------------
#
# World object
#
# Copyright (c) 2012 Fernando Garcia Huerta
# nanomuelle@gmail.com
#
#    This file is part of SimCell
#
#    SimCell is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    SimCell is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with SimAnim.  If not, see <http://www.gnu.org/licenses/>.
#
# ------------------------------------------------------------------------------

__author__    = "$Author$"
__revision__  = "$Revision$"
__date__      = "$Date: 16 Jan 2012 $"
__copyright__ = "2012 nanomuelle.com"
__contact__   = "http://blog.nanomuelle.com"

import random

from simcell.genetic.genetic_code import GeneticCode
from simcell.cell.cell import Cell
from simcell.world.organism import Organism

class World:
    def __init__(self, num_citizens = 100, len_adn = 100):
        self.cg = GeneticCode()    
        self.maxX = 400
        self.maxY = 400
        self.poss = {}
        self.cicleNum = 0
        self.new_organisms = []
        
        # generate initial unicellular aleat population
        self.population = []
        for i in range(num_citizens):
            adn = "".join(['0' if random.random() < 0.5 else '1' for x in range(len_adn)])
          
            organism = Organism(self)
            organism.pos = random.randint(0, self.maxX), random.randint(0, self.maxY)
          
            cell = Cell(self.cg, adn)
            for j in range(100):
              cell.cicle()
            
            cells = [cell]

            organism.cells = cells
          
            self.population.append(organism)
  
    def appendorganism(self, organism):
        self.neworganisms.append(organism)
    
    def cicle(self):
        self.cicleNum += 1
        self.poss = {}
        for organism in self.population:
            organism.cicle()
            if organism.pos in self.poss:
                (self.poss[organism.pos]).append(organism)
            else:
                self.poss[organism.pos] = [organism]
            
        for organism in self.new_organisms:
            self.population.append(organism)
          
        self.neworganisms = []
     
        #
        # Interactions
        #
        # When 2 organisms fall in the same position they interact,
        # all of them interact 2 by 2.
        #
        to_remove = []
        to_add = []
        for pos, vecinos in self.poss.iteritems():
            if len(vecinos) >= 2:
                pairs = [(x,y) for x in vecinos for y in vecinos if x <> y]       
                for pair in pairs:                    
                    new_organism = self.interact(pair[0], pair[1])
                    if not new_organism is None:
                        print "-> crossing..." + str(pair[0]) + " - " + str(pair[1])
                        # print ", ".join(map(str, self.population))
                        to_remove.append(pair[0])
                        to_remove.append(pair[1])
                        to_add.append(new_organism)
                
        for c in to_remove:
            if c in self.population:
                self.population.remove(c)

        for c in to_add:
            if not c in self.population:
                self.population.append(c)

        # move organisms
        for organism in self.population:
            organism.move()    
  
    def interact(self, organism1, organism2):
        cell1 = organism1.selectRandomCell()
        cell2 = organism2.selectRandomCell()
        
        # solo se permite interaccion en la fase de la celula G1
        if cell1.fase != 'G1' or cell2.fase != 'G1':
    #      print "   do not interact: selected cells not in G1."
          return None
          
        # y no en celulas que ya esten unidas entre si
        if cell1 in organism2.cells or cell2 in organism1.cells:
    #      print "   do not interact: selected cells already joined."
          return None
          
        num = cell1.membrana.interact(cell2.membrana)
    #    print "   do interact: on %d proteins!" % num
        
        if num > 0:
          organism1.cells.extend(organism2.cells)
          return organism1
        else:
          return None
    
    def printPopulation(self):
        for organism in self.population:
            print "\n".join(map(str, organism.info()))